# coding:utf-8
"""
    @project: automated_testing_platform
    @Author：caicaizi
    @file： base_web_driver.py
    @date：2023/5/17 23:29
"""
import re

import pytest
from time import sleep
from selenium import webdriver
from selenium.webdriver.remote.webdriver import WebElement, WebDriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support.select import Select
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.common.action_chains import ActionChains
from webdriver_manager.chrome import ChromeDriverManager
from webdriver_manager.firefox import GeckoDriverManager
from webdriver_manager.opera import OperaDriverManager
import cv2
from PIL import Image
import base64
from io import BytesIO

from apps.webcases.utils.cv2_utils import get_slider_instance


class BaseWebDriver:
    """定义web驱动类"""

    def __init__(self, executor=None, driver_name='chrome'):
        self.driver_name = driver_name
        if executor is None:
            self.__init_executor()
        else:
            self.driver: WebDriver = executor

    def __init_executor(self):
        """初始浏览器驱动"""
        if self.driver_name == 'chrome':
            self.driver: WebDriver = webdriver.Chrome(ChromeDriverManager().install())
        elif self.driver_name == 'firefox':
            self.driver: WebDriver = webdriver.Firefox(GeckoDriverManager().install())
        elif self.driver_name == 'opera':
            self.driver: WebDriver = webdriver.Opera(OperaDriverManager().install())
        self.driver.implicitly_wait(5)

    def get_executor(self) -> WebDriver:
        """获取测试执行器"""
        return self.driver

    def quit_driver(self):
        """退出浏览器"""
        if self.driver is not None:
            try:
                self.driver.quit()
                self.driver = None
            except Exception as e:
                raise e

    def sleep(self, value):
        try:
            sleep(int(value))
        except Exception as e:
            raise e

    def open_url(self, url):
        """打开网址"""
        try:
            self.driver.get(url)
        except Exception as e:
            raise e

    # 获取页面HTML源代码
    def get_page_source(self):
        try:
            return self.driver.page_source
        except Exception as e:
            raise e

    # 定位元素
    def get_element(self, by, pattern=None) -> WebElement:
        """获取单个元素"""
        try:
            if by == 'id':
                element = WebDriverWait(self.driver, 10, 0.5).until(lambda x: x.find_element(By.ID, pattern))
                return element
            elif by == 'class':
                element = WebDriverWait(self.driver, 10, 0.5).until(lambda x: x.find_element(By.CLASS_NAME, pattern))
                return element
            elif by == 'tag_name':
                element = WebDriverWait(self.driver, 10, 0.5).until(lambda x: x.find_element(By.TAG_NAME, pattern))
                return element
            elif by == 'css':
                element = WebDriverWait(self.driver, 10, 0.5).until(lambda x: x.find_element(By.CSS_SELECTOR, pattern))
                return element
            elif by == 'xpath':
                element = WebDriverWait(self.driver, 10, 0.5).until(lambda x: x.find_element(By.XPATH, pattern))
                return element
            elif by == 'link_text':
                element = WebDriverWait(self.driver, 10, 0.5).until(lambda x: x.find_element(By.LINK_TEXT, pattern))
                return element
            elif by == 'partial_link_text':
                element = WebDriverWait(self.driver, 10, 0.5).until(
                    lambda x: x.find_element(By.PARTIAL_LINK_TEXT, pattern))
                return element
        except Exception as e:
            raise e

    def get_elements(self, by, pattern) -> list[WebElement]:
        """获取一组元素"""
        try:
            if by == 'id':
                elements = WebDriverWait(self.driver, 10, 0.5).until(lambda x: x.find_elements(By.ID, pattern))
                return elements
            elif by == 'class':
                elements = WebDriverWait(self.driver, 10, 0.5).until(lambda x: x.find_elements(By.CLASS_NAME, pattern))
                return elements
            elif by == 'tag_name':
                elements = WebDriverWait(self.driver, 10, 0.5).until(lambda x: x.find_elements(By.TAG_NAME, pattern))
                return elements
            elif by == 'css':
                elements = WebDriverWait(self.driver, 10, 0.5).until(
                    lambda x: x.find_elements(By.CSS_SELECTOR, pattern))
                return elements
            elif by == 'xpath':
                elements = WebDriverWait(self.driver, 10, 0.5).until(lambda x: x.find_elements(By.XPATH, pattern))
                return elements
            elif by == 'link_text':
                elements = WebDriverWait(self.driver, 10, 0.5).until(lambda x: x.find_elements(By.LINK_TEXT, pattern))
                return elements
            elif by == 'partial_link_text':
                elements = WebDriverWait(self.driver, 10, 0.5).until(
                    lambda x: x.find_elements(By.PARTIAL_LINK_TEXT, pattern))
                return elements
        except Exception as e:
            raise e

    # 操作元素
    def click_element(self, by, pattern):
        """点击元素"""
        self.get_element(by=by, pattern=pattern).click()

    def clear_element(self, by, pattern):
        """清空元素"""
        try:
            self.get_element(by=by, pattern=pattern).clear()
        except Exception as e:
            raise e

    def send_keys(self, by, pattern, value):
        """输入信息"""
        try:
            self.get_element(by=by, pattern=pattern).send_keys(value)
        except Exception as e:
            raise e

    def submit(self, by, pattern):
        """提交表单"""
        try:
            self.get_element(by=by, pattern=pattern).submit()
        except Exception as e:
            raise e

    # 获取元素内容
    def get_text(self, by, pattern):
        """获取HTML元素的文本值"""
        try:
            return self.get_element(by=by, pattern=pattern).text
        except Exception as e:
            raise e

    def get_tag_name(self, by, pattern):
        """获取元素的标签类型"""
        try:
            return self.get_element(by=by, pattern=pattern).text
        except Exception as e:
            raise e

    def element_is_selected(self, by, pattern):
        """获取元素的选中状态"""
        try:
            return self.get_element(by=by, pattern=pattern).is_selected()
        except Exception as e:
            raise e

    def element_is_enabled(self, by, pattern):
        """获取元素的可编辑状态"""
        try:
            return self.get_element(by=by, pattern=pattern).is_enabled()
        except Exception as e:
            raise e

    def element_is_displayed(self, by, pattern):
        """判断元素是否已显示"""
        try:
            return self.get_element(by=by, pattern=pattern).is_displayed()
        except Exception as e:
            raise e

    # 获取元素的HTML属性
    def get_attribute(self, by, pattern, value):
        """获取元素的HTML属性"""
        try:
            return self.get_element(by=by, pattern=pattern).get_attribute(value)
        except Exception as e:
            raise e

    # 获取元素的DOM属性
    def get_property(self, by, pattern, value):
        """获取元素的DOM属性"""
        try:
            return self.get_element(by=by, pattern=pattern).get_property(value)
        except Exception as e:
            raise e

    # 获取页面元素的CSS属性值
    def get_css_property(self, by, pattern, value):
        """获取页面元素的CSS属性值"""
        try:
            return self.get_element(by=by, pattern=pattern).value_of_css_property(value)
        except Exception as e:
            raise e

    # 弹出框操作
    def accept_alert(self):
        try:
            self.driver.switch_to.alert.accept()
        except Exception as e:
            raise e

    def dismiss_alert(self):
        try:
            self.driver.switch_to.alert.dismiss()
        except Exception as e:
            raise e

    def get_alert_text(self):
        try:
            return self.driver.switch_to.alert.text
        except Exception as e:
            raise e

    def send_keys_to_alert(self, value):
        try:
            self.driver.switch_to.alert.send_keys(value)
        except Exception as e:
            raise e

    # 截图
    # 截取浏览器界面
    def get_windows_screenshot(self, filename):
        self.driver.get_screenshot_as_file(filename)

    def get_element_screenshot(self, by, pattern, filename):
        self.get_element(by, pattern).screenshot(filename)

    # 多网页切换操作
    # 多浏览器窗口的切换
    def get_current_window_handle(self):
        """获得WebDriver当前正在操作的浏览器窗口句柄"""
        try:
            return self.driver.current_window_handle
        except Exception as e:
            raise e

    def get_window_handles(self):
        """获得该WebDriver实例下的全部句柄"""
        try:
            return self.driver.window_handles
        except Exception as e:
            raise e

    def switch_to_window(self, handle):
        """切换到指定窗口"""
        try:
            self.driver.switch_to.window(handle)
        except Exception as e:
            raise e

    def switch_to_window_by_index(self, index):
        handles = self.get_window_handles()
        self.switch_to_window(handles[int(index)])

    # IFrame切换
    def switch_to_frame(self, by, pattern):
        """切换到当前页面（或IFrame）的下一级指定IFrame中"""
        try:
            frame = self.get_element(by, pattern)
            self.driver.switch_to.frame(frame)
        except Exception as e:
            raise e

    def switch_to_parent_frame(self):
        """切换到当前IFrame的上一级页面（或IFrame）中"""
        try:
            self.driver.switch_to.parent_frame()
        except Exception as e:
            raise e

    # 下拉框元素的选项操作
    def select_by_text(self, by, pattern, value):
        """按文本选择下拉框"""
        try:
            selectWebElement = Select(self.get_element(by, pattern))
            selectWebElement.select_by_visible_text(value)
        except Exception as e:
            raise e

    def select_by_index(self, by, pattern, value):
        """按索引选择下拉框"""
        try:
            selectWebElement = Select(self.get_element(by, pattern))
            selectWebElement.select_by_index(value)
        except Exception as e:
            raise e

    def select_by_value(self, by, pattern, value):
        """按选项值选择下拉框"""
        try:
            selectWebElement = Select(self.get_element(by, pattern))
            selectWebElement.select_by_value(value)
        except Exception as e:
            raise e

    def deselect_all(self, by, pattern):
        """取消所有选项"""
        try:
            selectWebElement = Select(self.get_element(by, pattern))
            selectWebElement.deselect_all()
        except Exception as e:
            raise e

    def deselect_by_value(self, by, pattern, value):
        """按选项值取消选项"""
        try:
            selectWebElement = Select(self.get_element(by, pattern))
            selectWebElement.deselect_by_value(value)
        except Exception as e:
            raise e

    def deselect_by_index(self, by, pattern, value):
        """按索引值取消选项"""
        try:
            selectWebElement = Select(self.get_element(by, pattern))
            selectWebElement.deselect_by_index(value)
        except Exception as e:
            raise e

    def deselect_by_visible_text(self, by, pattern, value):
        """按文本取消选项"""
        try:
            selectWebElement = Select(self.get_element(by, pattern))
            selectWebElement.deselect_by_visible_text(value)
        except Exception as e:
            raise e

    # driver.back()  # 后退
    def back(self):
        try:
            self.driver.back()
        except Exception as e:
            raise e

    # driver.forward()  # 前进
    def forward(self):
        try:
            self.driver.forward()
        except Exception as e:
            raise e

    # driver.refresh()  # 刷新
    def refresh(self):
        try:
            self.driver.refresh()
        except Exception as e:
            raise e

    # driver.minimize_window()  # 最小化窗口
    def minimize_window(self):
        try:
            self.driver.minimize_window()
        except Exception as e:
            raise e

    # driver.maximize_window()  # 最大化窗口
    def maximize_window(self):
        try:
            self.driver.maximize_window()
        except Exception as e:
            raise e

    # driver.close()  # 关闭窗口
    def close(self):
        try:
            self.driver.close()
        except Exception as e:
            raise e

    # driver.title  # 获取浏览器窗口当前的标题
    def get_driver_title(self):
        try:
            return self.driver.title
        except Exception as e:
            raise e

    # driver.current_url  # 获取浏览器窗口当前的网址
    def get_current_url(self):
        try:
            return self.driver.current_url
        except Exception as e:
            raise e

    # driver.get_window_position()  # 获取位置对象
    # driver.get_window_size()  # 获取大小对象
    # driver.get_window_rect()  # 获取位置及大小对象
    # webElement.value_of_css_property("CSS属性名称")  # 获取元素的CSS属性
    # webElement.location  # 获取位置对象
    # webElement.size  # 获取大小对象
    # webElement.rect  # 获取位置及大小对象
    # SelectWebElement.first_selected_option  # 获取首个已选中项（类型为WebElement）
    # SelectWebElement.all_selected_options  # 获取全部已选中项（类型为WebElement数组）
    # SelectWebElement.options  # 获取下拉框提供的所有选项（无论是否已选中，类型为WebElement数组）
    # 断言

    # 鼠标事件
    # 右击
    def context_click_element(self, by, pattern):
        """右击"""
        try:
            element = self.get_element(by=by, pattern=pattern)
            action_chains = ActionChains(self.driver)
            action_chains.context_click(element).perform()
        except Exception as e:
            raise e

    # 双击
    def double_click_element(self, by, pattern):
        """双击元素"""
        try:
            element = self.get_element(by=by, pattern=pattern)
            ActionChains(self.driver).double_click(element).perform()
        except Exception as e:
            raise e

    # 拖动
    def drag_and_drop_by_offset(self, by, pattern, value):
        element = self.get_element(by, pattern)
        ActionChains(self.driver).drag_and_drop_by_offset(element, value, 0).perform()

    def drag_and_drop_slider(self, by, pattern):
        value = get_slider_instance('assert/images/slider_imgs/2.png',
                                    'assert/images/slider_imgs/1.png')
        self.drag_and_drop_by_offset(by, pattern, value)

    # 鼠标悬停
    def move_to_element(self, by, pattern):
        """双击元素"""
        try:
            element = self.get_element(by=by, pattern=pattern)
            ActionChains(self.driver).move_to_element(element).perform()
        except Exception as e:
            raise e

    # 点击左键并保持
    def click_and_hold(self, by, pattern):
        """双击元素"""
        try:
            element = self.get_element(by=by, pattern=pattern)
            ActionChains(self.driver).click_and_hold(element).perform()
        except Exception as e:
            raise e

    # 键盘事件
    #
    # base64
    def get_base64_image_path(self, by, pattern, value):
        if value == 'src':
            image_data = self.get_attribute(by, pattern, value)
        else:
            canvas = self.get_attribute(by, pattern, value)
            image_data = re.findall("(data:image/jpg;base64,.*?)\"\)", canvas)[0]
        return image_data

    def open_base64_image(self, by, pattern, value):
        image_data = self.get_base64_image_path(by, pattern, value)
        sleep(2)
        # 打开新的标签页
        self.execute_script("window.open('','_blank');")
        sleep(2)
        handles = self.get_window_handles()
        self.switch_to_window(handles[-1])
        self.open_url(image_data)

    # 执行js脚本
    def execute_script(self, script):
        self.driver.execute_script(script)


if __name__ == '__main__':
    driver = BaseWebDriver()
    driver.open_url('http://www.baidu.com')
    driver.maximize_window()
    current_handle = driver.get_current_window_handle()
    sleep(2)
    js = f"window.open('','_blank');"  # 打开新标签页
    driver.open_url('https://etax.hunan.chinatax.gov.cn/wsbs/')
    driver.quit_driver()
